import cv2
import numpy as np
import matplotlib.pyplot as plt

def show_noise_effect_demo(img_gray, low_threshold, high_threshold, blur_ksize):
    print("\n--- 演示Canny的抗噪能力 (但并非绝对完美) ---")
    # 故意添加更多噪声到原始图像
    noisy_img_raw = img_gray.copy()
    noise = np.random.normal(0, 30, noisy_img_raw.shape).astype(np.uint8) # 较高强度的噪声
    noisy_img_raw = cv2.add(noisy_img_raw, noise)

    # 对含噪声的图像进行Canny检测
    # 尝试调整模糊核大小，看看抗噪效果
    blurred_noisy_img = cv2.GaussianBlur(noisy_img_raw, blur_ksize, 0)
    edges_noisy = cv2.Canny(blurred_noisy_img, low_threshold, high_threshold)

    plt.figure(figsize=(18, 6))
    plt.subplot(1, 3, 1)
    plt.imshow(noisy_img_raw, cmap='gray')
    plt.title('Original Image with Added Noise')
    plt.axis('off')

    plt.subplot(1, 3, 2)
    plt.imshow(blurred_noisy_img, cmap='gray')
    plt.title(f'Noisy Image after Gaussian Blur (Kernel={blur_ksize})')
    plt.axis('off')

    plt.subplot(1, 3, 3)
    plt.imshow(edges_noisy, cmap='gray')
    plt.title(f'Canny Edges on Noisy Image')
    plt.axis('off')
    plt.tight_layout()
    plt.show()

def canny_edge_detection_demo(image_path, low_threshold=50, high_threshold=150, blur_ksize=(5, 5)):
    """
    演示 Canny 边缘检测的工作原理。
    
    Args:
        image_path (str): 待处理图像的路径。
        low_threshold (int): 双阈值处理的低阈值。
        high_threshold (int): 双阈值处理的高阈值。
        blur_ksize (tuple): 高斯模糊核的大小 (宽度, 高度)。
    """
    # 1. 加载图像
    img_bgr = cv2.imread(image_path)
    if img_bgr is None:
        print(f"Error: Could not load image from {image_path}")
        return

    img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

    # --- Canny 算法核心步骤可视化 ---

    # 1. 高斯模糊 (Noise Reduction)
    # 我们将清晰地看到模糊后的效果，以及它如何去除部分噪声
    blurred_img = cv2.GaussianBlur(img_gray, blur_ksize, 0)

    # 2. 计算图像梯度强度和方向 (OpenCV Canny内部完成，但我们知道它在这里发生)
    # 这一步通常不单独可视化，因为它是Canny内部的计算，但我们可以理解它在进行。

    # 3. 非极大值抑制 (NMS) 和 4. 双阈值处理 和 5. 边缘跟踪
    # OpenCV 的 cv2.Canny() 函数将这三步封装在一起。
    # 为了保持简洁性，我们直接调用它，但要理解这背后包含了复杂的逻辑。
    edges = cv2.Canny(blurred_img, low_threshold, high_threshold)

    # --- 可视化所有关键步骤 ---
    plt.figure(figsize=(18, 6)) # 调整图表大小以适应更多子图

    # 原始灰度图
    plt.subplot(1, 3, 1)
    plt.imshow(img_gray, cmap='gray')
    plt.title('1. Original Grayscale Image')
    plt.axis('off')

    # 高斯模糊后的图像
    plt.subplot(1, 3, 2)
    plt.imshow(blurred_img, cmap='gray')
    plt.title(f'2. Gaussian Blurred (Kernel={blur_ksize})')
    plt.axis('off')

    # Canny 边缘检测结果 (包含了NMS、双阈值、边缘跟踪)
    plt.subplot(1, 3, 3)
    plt.imshow(edges, cmap='gray')
    plt.title(f'3. Canny Edges (Low={low_threshold}, High={high_threshold})')
    plt.axis('off')

    plt.tight_layout()
    plt.show()

    # 调用噪声演示函数
    #show_noise_effect_demo(img_gray, low_threshold, high_threshold, blur_ksize)


if __name__ == "__main__":
    # 请确保你有一张名为 'test_image.jpg' 的图片在当前目录下
    # 或者替换成你自己的图片路径，例如 'path/to/your/image.jpg'
    image_path = './edge_detection_canny/test_image.jpg'

    print("--- 运行 Canny 边缘检测 Demo (默认参数) ---")
    canny_edge_detection_demo(image_path)

    # print("\n--- 调整 Canny 参数来观察效果 ---")
    # print("尝试更低的阈值 (可能引入更多细节和噪声)")
    # canny_edge_detection_demo(image_path, low_threshold=30, high_threshold=90)

    # print("\n尝试更高的阈值 (可能丢失细微边缘，导致断裂)")
    # canny_edge_detection_demo(image_path, low_threshold=80, high_threshold=200)

    # print("\n尝试更大的高斯模糊核 (边缘可能更平滑但丢失细节)")
    # canny_edge_detection_demo(image_path, blur_ksize=(9, 9))

    # print("\n尝试更小的高斯模糊核 (抗噪能力下降，边缘可能更粗糙)")
    # canny_edge_detection_demo(image_path, blur_ksize=(3, 3))